<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:h="http://apache.org/cocoon/request/2.0" xmlns:cu="http://apache.org/cocoon/counit"
  version="1.0">
  <xsl:param name="uri-prefix"/>
  <xsl:param name="src"/>
  <!-- is passed by the mount table matcher -->
  <xsl:param name="sitemap-uri-prefix"/>

  <!-- 
    inspects the uri-prefix and request parameters and finds the corresponding testsuite.xml.
    If the uri contains a reference to a testcase ( /counit/blah/testcase-id), it will 
    find the testcase in the testsuite.xml.
    If the URL ends with a slash, it is assumed that no testcase-id is given.
    
    Authors: Jan Willem Boer <janwillem@jwenr.nl>
  -->

  <!-- the testsuite.xml filename -->
  <xsl:variable name="testsuite-dir">.counit/</xsl:variable>
  <!-- don't forget the slash -->
  <xsl:variable name="testsuite-file">testsuite.xml</xsl:variable>

  <xsl:template match="h:request">
    <!-- 
      /counit/(test|report)/HelloWorld/ByeWorld/testcase

      @target == /counit/(test|report)/HelloWorld/ByeWorld/testcase
      $uri-prefix == HelloWorld/
      $src == file://D:/Projecten/XmlOntwikkelstraat/CoUnit/HelloWorld/
      $sitemap-uri-prefix == counit
      
    -->
    <xsl:variable name="sitemap-uri"
      select="substring-after(substring-after(@target, $sitemap-uri-prefix), '/')"/>
    <!-- 
      sitemap-uri == HelloWorld/ByeWorld/testcase
    -->

    <!-- find the difference between the uri-prefix and the request target -->
    <xsl:variable name="difference">
      <xsl:if test="string-length($sitemap-uri) != string-length($uri-prefix)">
        <xsl:value-of select="substring($sitemap-uri, string-length($uri-prefix) + 1)"/>
      </xsl:if>
    </xsl:variable>
    <!-- 
      $difference == ByeWorld/testcase
    -->

    <!-- determine if there is a testcase (ByeWorld/ doesn't have a testcase ByeWorld/testcase does) -->
    <xsl:variable name="has-testcase"
      select="not(substring($difference,  string-length($difference), 1) = '/')"/>

    <!-- find directory containing testsuite -->
    <xsl:variable name="postfix-path">
      <xsl:choose>
        <xsl:when test="$has-testcase">
          <!-- contains a testcase. Find the first / from right -->
          <xsl:variable name="postfix-first-pass">
            <xsl:call-template name="revert">
              <xsl:with-param name="text">
                <xsl:variable name="reverted">
                  <xsl:call-template name="revert">
                    <xsl:with-param name="text" select="$difference"/>
                  </xsl:call-template>
                </xsl:variable>
                <xsl:value-of select="substring-after($reverted, '/')"/>
              </xsl:with-param>
            </xsl:call-template>
          </xsl:variable>
          <xsl:value-of select="$postfix-first-pass"/>
          <!-- add a trailing slash if postfix contains a path -->
          <xsl:if test="string-length($postfix-first-pass) &gt; 0">
            <xsl:text>/</xsl:text>
          </xsl:if>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$difference"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <!-- 
      $postfix-path == ByeWorld/
    -->

    <!-- find the testcase (if any) -->
    <xsl:variable name="testcase-id">
      <xsl:if test="$has-testcase">
        <xsl:value-of select="substring-after($difference, $postfix-path)"/>
      </xsl:if>
    </xsl:variable>
    <!-- 
      $testcase-id == testcase
    -->

    <xsl:variable name="base" select="concat($src, $postfix-path)"/>
    <xsl:variable name="testsuite-path" select="concat($base, $testsuite-dir, $testsuite-file)"/>
    <!-- load the external testsuite document -->
    <xsl:apply-templates select="document($testsuite-path)/*" mode="copy">
      <xsl:with-param name="testcase-id" select="$testcase-id"/>
      <xsl:with-param name="base" select="$base"/>
      <xsl:with-param name="testsuite-dir" select="$testsuite-dir"/>
      <xsl:with-param name="counit-url"
        select="concat('http://', //h:header[@name='Host'], '/', $sitemap-uri-prefix)"/>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="node()|@*" mode="copy">
    <xsl:param name="testcase-id"/>
    <xsl:element namespace="http://apache.org/cocoon/counit" name="cu:{local-name()}">
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates select="node()" mode="copy">
        <xsl:with-param name="testcase-id" select="$testcase-id"/>
      </xsl:apply-templates>
    </xsl:element>
  </xsl:template>

  <xsl:template match="testcase" mode="copy">
    <xsl:param name="testcase-id"/>
    <xsl:if test="string-length($testcase-id) = 0 or $testcase-id = @id">
      <xsl:element namespace="http://apache.org/cocoon/counit" name="cu:{local-name()}">
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates select="node()" mode="copy"/>
      </xsl:element>
    </xsl:if>
  </xsl:template>

  <xsl:template match="testsuite" mode="copy">
    <xsl:param name="base"/>
    <xsl:param name="testsuite-dir"/>
    <xsl:param name="counit-url"/>
    <xsl:param name="testcase-id"/>

    <xsl:choose>
      <xsl:when test="@src">
        <!-- a testsuite should be mounted here -->
        <xsl:variable name="new-base" select="concat($base, @src)"/>
        <xsl:apply-templates select="document(concat($new-base, $testsuite-dir, $testsuite-file))/*"
          mode="copy">
          <xsl:with-param name="testcase-id" select="$testcase-id"/>
          <xsl:with-param name="base" select="$new-base"/>
          <xsl:with-param name="testsuite-dir" select="$testsuite-dir"/>
          <xsl:with-param name="counit-url" select="$counit-url"/>
        </xsl:apply-templates>
      </xsl:when>
      <xsl:otherwise>
        <!-- a normal, inline, testsuite -->
        <xsl:element namespace="http://apache.org/cocoon/counit" name="cu:{local-name()}">
          <xsl:copy-of select="@*"/>
          <xsl:attribute name="base">
            <xsl:value-of select="$base"/>
          </xsl:attribute>
          <xsl:attribute name="testsuite-dir">
            <xsl:value-of select="$testsuite-dir"/>
          </xsl:attribute>
          <xsl:attribute name="counit-url">
            <xsl:value-of select="$counit-url"/>
          </xsl:attribute>
          <xsl:apply-templates select="node()" mode="copy">
            <xsl:with-param name="testcase-id" select="$testcase-id"/>
            <xsl:with-param name="base" select="$base"/>
            <xsl:with-param name="testsuite-dir" select="$testsuite-dir"/>
            <xsl:with-param name="counit-url" select="$counit-url"/>
          </xsl:apply-templates>
        </xsl:element>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- copy nodes with content that is not in the counit namespace -->
  <xsl:template match="expect|configuration|input" mode="copy">
    <xsl:element namespace="http://apache.org/cocoon/counit" name="cu:{local-name()}">
      <xsl:copy-of select="@*|node()"/>
    </xsl:element>
  </xsl:template>

  <!-- input element may have stuff in the counit namespace -->
  <xsl:template match="input[@preprocess='true']" mode="copy">
    <xsl:element namespace="http://apache.org/cocoon/counit" name="cu:{local-name()}">
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates select="node()" mode="copy"/>
    </xsl:element>
  </xsl:template>
  
  <!-- revert needed to find the last occurrance of a string in another string -->
  <xsl:template match="text()" name="revert">
    <xsl:param name="text" select="."/>
    <xsl:if test="string-length($text) &gt; 0">
      <xsl:value-of select="substring($text, string-length($text), 1)"/>
      <xsl:call-template name="revert">
        <xsl:with-param name="text" select="substring($text, 1, string-length($text) - 1)"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>
